#!/usr/bin/php
<?

// Mates! - Simulator (for demos)
// Authors:
//   Ayush Agarwal <yush@umich.edu>
//   Adam Herscher <ahersche@umich.edu>
//   Jeff Powers <jrpowers@umich.edu>

// Path to mates htdocs
$MATES_PATH = "/home/mates/htdocs/mates0.4";
require_once("$MATES_PATH/nusoap.php");

if (($argc != 2) || (intval($argv[1]) < 0) || (intval($argv[1]) > 200))
  die("Usage: {$argv[0]} [# users (0-200)]\n");

// Lists of users and potential interests, courses, and locations

// Make sure this list is kept in sync with the list in mates_simulator_reset.php!
$_GLOBALS["MAX_FRIENDS"] = 50; // max # of friends for each user [must be smaller than count($users)]
$users_sexist = array(
'Jacob', 'Aidan', 'Ethan', 'Ryan', 'Matthew', 'Michael', 'Tyler', 'Joshua', 'Nicholas', 'Connor', 'Zachary', 'Andrew', 'Dylan', 'Jack', 'Jayden', 'Logan', 'Caden', 'Caleb', 'Alexander', 'Nathan', 'Noah', 'William', 'Jackson', 'Joseph', 'Christopher', 'James', 'Daniel', 'Benjamin', 'Anthony', 'Cameron', 'Austin', 'Evan', 'Luke', 'Gavin', 'Brayden', 'Brandon', 'Christian', 'John', 'David', 'Sean', 'Gabriel', 'Jonathan', 'Samuel', 'Elijah', 'Colin', 'Justin', 'Alex', 'Mason', 'Jordan', 'Thomas', 'Hunter', 'Lucas', 'Kyle', 'Owen', 'Jake', 'Devin', 'Jason', 'Liam', 'Cole', 'Adam', 'Dominic', 'Aaron', 'Ian', 'Hayden', 'Isaac', 'Robert', 'Carter', 'Isaiah', 'Chase', 'Landon', 'Riley', 'Eric', 'Max', 'Nathaniel', 'Tristan', 'Brian', 'Ashton', 'Brendan', 'Cody', 'Carson', 'Julian', 'Wyatt', 'Blake', 'Seth', 'Sebastian', 'Xavier', 'Will', 'Bryce', 'Garrett', 'Kevin', 'Sam', 'Patrick', 'Brady', 'Charlie', 'Parker', 'Trevor', 'Charles', 'Cooper', 'Timothy', 'Henry', 'Emma', 'Madison', 'Emily', 'Kaitlyn', 'Hailey', 'Olivia', 'Isabella', 'Hannah', 'Sarah', 'Abigail', 'Sophia', 'Kaylee', 'Alyssa', 'Madeline', 'Brianna', 'Grace', 'Alexis', 'Sydney', 'Samantha', 'RileyB', 'Lauren', 'Taylor', 'Chloe', 'Ella', 'Ava', 'Elizabeth', 'Ashley', 'Makayla', 'Lily', 'Anna', 'Kayla', 'Megan', 'Zoe', 'Mackenzie', 'Kylie', 'Natalie', 'Allison', 'Maya', 'Katherine', 'Morgan', 'Mia', 'Jasmine', 'Isabel', 'JordanB', 'Rachel', 'Julia', 'Jessica', 'Savannah', 'Ariana', 'Victoria', 'Paige', 'Avery', 'Abby', 'Trinity', 'Brooke', 'Katie', 'Peyton', 'Alexandra', 'Jaydn', 'Rebecca', 'Jenna', 'Bailey', 'Leah', 'Gabriella', 'Faith', 'Caroline', 'Sophie', 'Nicole', 'Audrey', 'Gabrielle', 'Lillian', 'Molly', 'Ashlyn', 'Claire', 'Kennedy', 'Amelia', 'Gracie', 'Marissa', 'Amanda', 'Erin', 'Destiny', 'Reagan', 'Kate', 'Brooklyn', 'Alexa', 'Jada', 'Mary', 'Angelina', 'Ellie', 'Danielle', 'Aaliyah', 'Alicia', 'Sierra', 'Gianna', 'Kendall', 'Charlotte', 'Maria', 'Autumn', 'Shelby', 'Amber');

$users = array();
$fwd = 0;
$bwd = 199;
for($i = 0; $i < 200; $i++)
  if ($i % 2)
    array_push($users, $users_sexist[$fwd++]);
  else
    array_push($users, $users_sexist[$bwd--]);

for($i = 0; $i < 200 - intval($argv[1]); $i++)
  array_pop($users);

$interests = array(
"North Campus Volleyball",
"Computer Science",
"The Discovery Channel",
"MUJO Coffee",
"Solar Car Team",
"GROCS",
"UM Waterski Team",
"Underwater Basket Weaving",
"Jazz Music",
"gEECS",
"The Michigan Daily",
"Location-based services",
"EECS Student Advising",
"EECS Peer Tutoring",
"CAEN Staff",
"EECS 280 GSIs",
"Robotics",
"Slashdot",
"Michigan Inspire",
"CTools Developers",
"Coding competitions",
"AI Lab groupies",
"HKN",
"Snowboarding",
"Spring Break 2005",
"CSE Scholars",
"Orientation Group Leaders",
"Computational theory",
"Theoretical math",
"Technology in education",
"Microsoft tech talks",
"Applied math",
"Google tech talks"
);

$courses = array(
"EECS 281",
"EECS 370",
"SOC 330",
"SI 110",
"HIST 195",
"EECS 280",
"EECS 584",
"EECS 547",
"EECS 482",
"EECS 203",
"CHEM 130",
"CHEM 125",
"PHYS 240",
"PHYS 241",
"EECS 373",
"EECS 484",
"MATH 425",
"EECS 584",
"NES 100",
"MATH 215",
"STAT 412",
"EECS 206",
"EECS 376",
"EECS 492"
);

$locs = array(
array("MUJO", 42.2911, -83.7161),
array("Media Union 2S", 42.2912, -83.7161),
array("Design Lab One", 42.2893, -83.7141),
array("EECS", 42.2914, -83.7123),
array("Pierpont Commons", 42.2909, -83.7151),
array("Prof. Soloway Office", 42.2901, -83.7156),
array("Lurie Advising Office", 42.2898, -83.7141),
array("CCA", 42.2913, -83.7162)
);

$messages = array(
'Hey, Im giving a talk in Chesebrough Auditorium later this afternoon.  Are you interested in attending?',
'Did you understand that ARIES recovery algorithm in 484 today?',
'Wanna meet up and study with a few of us in the conference room down the hall?',
'Have you seen mates yet?  What an awesome application!',
'It is unwise to be too sure of ones own wisdom. It is healthy to be reminded that the strongest might weaken and the wisest might err.',
'Not everything that can be counted counts, and not everything that counts can be counted.',
'The use of COBOL cripples the mind; its teaching should, therefore, be regarded as a criminal offense.',
'A mathematician is a device for turning coffee into theorems.',
'The power of accurate observation is frequently called cynicism by those who do not have it.',
'Most folks are as happy as they make up their minds to be.',
'Surround yourself with only people who are going to lift you higher.'
);

$walls = array(
'Check out the Inspire Fair on April 14th!',
'Adam was here.',
'This location is special.',
'Time to graduate!!!!!!!!!!!!!!!',
'Do you Yahoo?',
'mates is cool.',
'If I had something inspirational to share, I would put it here.'
);

// Soap client initialization
echo "Initializing soap client... ";
$basetime = microtime();
$client = new soapclient('http://141.213.30.62/mates0.4/mates.php');
echo number_format(microtime() - $basetime, 3), "s\n";

// create a user object for each user
echo "Constructing dummy user objects ";
$basetime = microtime();
$client = new soapclient('http://141.213.30.62/mates0.4/mates.php');
foreach ($users as $user)
  $$user = new user("$user", "{$user}123");
echo "(", count($users), ")... ", number_format(microtime() - $basetime, 3), "s\n";

// Initial login, setloc, and addition of many interests, courses, and friends
echo "Registering dummy users ";
$basetime = microtime_float();
foreach ($users as $user)
  $$user->register($client);
echo "(", count($users), ")... ", number_format(microtime_float() - $basetime, 3), "s\n";

echo "Logging dummy users in ";
$basetime = microtime_float();
foreach ($users as $user)
  $$user->login($client);
echo "(", count($users), ")... ", number_format(microtime_float() - $basetime, 3), "s\n";

echo "Setting dummy user locations ";
$basetime = microtime_float();
foreach ($users as $user) {
  $locnum = rand(0, count($locs) - 1);
  $$user->setloc($client, $locs[$locnum][0], $locs[$locnum][1], $locs[$locnum][2]);
}
echo "(", count($users), ")... ", number_format(microtime_float() - $basetime, 3), "s\n";

echo "Setting dummy user profiles ";
$basetime = microtime_float();
foreach ($users as $user)
  $$user->setuserinfo($client, "$user is a silly simulated user who enjoys long rides on the bus with his silly simulated friends.");
echo "(", count($users), ")... ", number_format(microtime_float() - $basetime, 3), "s\n";

echo "Loading dummy user interests ";
$basetime = microtime_float();
$total_interests = 0;
foreach ($users as $user) {
  $numinterests = rand(5, 15);
  for ($i = 0; $i < $numinterests; $i++) {
    $interestnum = rand(0, count($interests) - 1);
    $$user->interest_add($client, $interests[$interestnum]);
    $total_interests++;
  }
}
echo "($total_interests)... ", number_format(microtime_float() - $basetime, 3), "s\n";

echo "Loading dummy user courses ";
$basetime = microtime_float();
$total_courses = 0;
foreach ($users as $user) {
  $numcourses = rand(3, 6);
  for ($i = 0; $i < $numcourses; $i++) {
    $coursenum = rand(0, count($courses) - 1);
    $$user->course_add($client, $courses[$coursenum]);
    $total_courses++;
  }
}
echo "($total_courses)... ", number_format(microtime_float() - $basetime, 3), "s\n";

echo "Loading dummy user friends... ";
$basetime = microtime_float();
$total_friends = 0;
foreach ($users as $user) {
  $numfriends = rand(5, $_GLOBALS["MAX_FRIENDS"]);
  for ($i = 0; $i < $numfriends; $i++) {
    $friendnum = rand(0, count($users) - 1);
    if ($users[$friendnum] != $$user->username) {
      $$user->friend_add($client, $users[$friendnum]);
      $total_friends++;
    }
  }
}
echo "($total_friends)... ", number_format(microtime_float() - $basetime, 3), "s\n";


// Continuous simulation
echo "Entering simulation loop...\n";
while (TRUE) {
  // pick a random user that will perform some action
  $usernum = rand(0, count($users) - 1);
  $user =& ${$users[$usernum]};
  echo $user->username;
  
  $basetime = microtime_float();
 
  // pick a random action to perform
  $action = rand(0, 8);
  switch($action) {
  case 0: // add interest
    echo " adds an interest (";
    $interestnum = rand(0, count($interests) - 1);
    $user->interest_add($client, $interests[$interestnum]);
    echo $interests[$interestnum] . ")... ", number_format(microtime_float() - $basetime, 3), "s\n";
    break;
  case 1: // delete interest
    echo " deletes an interest (";
    $interestnum = rand(0, count($user->interests) - 1);
    $interest = $user->interests[$interestnum];
    $user->interest_del($client, $user->interests[$interestnum]);
    echo $interest . ")... ", number_format(microtime_float() - $basetime, 3), "s\n";
    break;
  case 2: // add course
    echo " adds a course (";
    $coursenum = rand(0, count($courses) - 1);
    $user->course_add($client, $courses[$coursenum]);
    echo $courses[$coursenum] . ")... ", number_format(microtime_float() - $basetime, 3), "s\n";
    break;
  case 3: // delete course
    echo " deletes a course (";
    $coursenum = rand(0, count($user->courses) - 1);
    $course = $user->courses[$coursenum];
    $user->course_del($client, $user->courses[$coursenum]);
    echo $course . ")... ", number_format(microtime_float() - $basetime, 3), "s\n";
    break;
  case 4: // add friend
    echo " adds a friend (";
    $friendnum = rand(0, count($users) - 1);
    $user->friend_add($client, $users[$friendnum]);
    echo $users[$friendnum] . ")... ", number_format(microtime_float() - $basetime, 3), "s\n";
    break;
  case 5: // delete friend
    echo " deletes a friend (";
    $friendnum = rand(0, count($user->friends) - 1);
    $friend = $user->friends[$friendnum];
    $user->friend_del($client, $user->friends[$friendnum]);
    echo $friend . ")... ", number_format(microtime_float() - $basetime, 3), "s\n";
    break;
  case 6: // send message
    echo " sends a message to ";
    $msgnum = rand(0, count($messages) - 1);
//    echo "[msgnum: " . $msgnum . "] ";

//    $rcptnum = rand(0, count($users) - 1);
//    $user->sendmsg($client, $users[$rcptnum], $messages[$msgnum]);
//    echo $users[$rcptnum] . " (\"" . $messages[$msgnum] . "\")... ", number_format(microtime_float() - $basetime, 3), "s\n";
    $user->sendmsg($client, "Jeff", $messages[$msgnum]);
    echo "Jeff (\"" . $messages[$msgnum] . "\")... ", number_format(microtime_float() - $basetime, 3), "s\n";
    break;
  case 7: // change location
    echo " switches location to ";
    $locnum = rand(0, count($locs) - 1);
    $user->setloc($client, $locs[$locnum][0], $locs[$locnum][1], $locs[$locnum][2]);
    echo $locs[$locnum][0] . "... ", number_format(microtime_float() - $basetime, 3), "s\n";
    break;
  case 8: // change the wall
    echo " changes his/her location's wall to ";
    $wallnum = rand(0, count($walls) - 1);
    $user->changewall($client, $walls[$wallnum]);
    echo "\"" . $walls[$wallnum] . "\"... ", number_format(microtime_float() - $basetime, 3), "s\n";
    break;
  }

  usleep(500000); // .5 seconds
}


// Classes and helper functions
class user
{
  var $username;
  var $password;
  var $loc_id;
  var $session_id;
  var $interests;
  var $courses;
  var $friends;

  function user($username, $password) {
    $this->username = $username;
    $this->password = $password;
    $this->interests = array();
    $this->courses = array();
    $this->friends = array();
  }
  
  function register($client) {
    $input = array('username' => $this->username, 'password' => $this->password);
    $output = $client->call('register', $input);
    check_err($output, $client);
    $this->session_id = $output['session_id'];
  }
  
  function login($client) {
    $input = array('username' => $this->username, 'password' => $this->password);
    $output = $client->call('login', $input);
    check_err($output, $client);
    $this->session_id = $output['session_id'];
  }

  function setuserinfo($client, $profile) {
    $input = array('session_id' => $this->session_id, 'msg' => $profile);
    $output = $client->call('setuserinfo', $input);
    check_err($output, $client);
  }
    
  function setloc($client, $name, $lat, $long) {
    $input = array('session_id' => $this->session_id, 'name' => $name, 'lat' => $lat, 'long' => $long, 'loc_id' => 0, 'mac_addr' => '00:00:00:00:00:00');
    $output = $client->call('setloc', $input);
    check_err($output, $client);
    $this->loc_id = $output['loc_id'];
  }
  
  function interest_add($client, $interest) {
    // for simulator simplicity, if the interest already exists don't add it again, but don't throw an error
    if (array_search($interest, $this->interests) === FALSE) {
      $input = array('session_id' => $this->session_id, 'interest' => $interest);
      $output = $client->call('interest_add', $input);
      check_err($output, $client);
      $this->interests[] = $interest;
    }
  }

  function interest_del($client, $interest) {
    if (empty($this->interests))
      return;
    $input = array('session_id' => $this->session_id, 'interest' => $interest);
    $output = $client->call('interest_del', $input);
    check_err($output, $client);
    
    // for the purpose of this simulator, we assume the item being deleted does exist
    // (i.e. i'm not error checking)
    $key = array_search($interest, $this->interests);
    unset($this->interests[$key]);
    $this->interests = array_values($this->interests);
  }

  function course_add($client, $course) {
    // for simulator simplicity, if the course already exists don't add it again, but don't throw an error
    if (array_search($course, $this->courses) === FALSE) {
      $input = array('session_id' => $this->session_id, 'course' => $course);
      $output = $client->call('course_add', $input);
      check_err($output, $client);
      $this->courses[] = $course;
    }
  }
  
  function course_del($client, $course) {
    if (empty($this->courses))
      return;
    $input = array('session_id' => $this->session_id, 'course' => $course);
    $output = $client->call('course_del', $input);
    check_err($output, $client);
    
    // for the purpose of this simulator, we assume the item being deleted does exist
    // (i.e. i'm not error checking)
    $key = array_search($course, $this->courses);
    unset($this->courses[$key]);
    $this->courses = array_values($this->courses);
  }
  
  function friend_add($client, $friend) {
    // for simulator simplicity, if the friend already exists don't add it again, but don't throw an error
    if (array_search($friend, $this->friends) === FALSE) {
      $input = array('session_id' => $this->session_id, 'friend' => $friend);
      $output = $client->call('friend_add', $input);
      check_err($output, $client);
      $this->friends[] = $friend;
    }
  }
  
  function friend_del($client, $friend) {
    if (empty($this->friends))
      return;
    $input = array('session_id' => $this->session_id, 'friend' => $friend);
    $output = $client->call('friend_del', $input);
    check_err($output, $client);
    
    // for the purpose of this simulator, we assume the item being deleted does exist
    // (i.e. i'm not error checking)
    $key = array_search($friend, $this->friends);
    unset($this->friends[$key]);
    $this->friends = array_values($this->friends);
  }

  function sendmsg($client, $rcpt, $message) {
    $input = array('session_id' => $this->session_id, 'username' => $rcpt, 'msg' => $message);
    $output = $client->call('sendmsg', $input);
    check_err($output, $client);
  }
  function changewall($client, $wall) {
    $input = array('session_id' => $this->session_id, 'msg' => $wall);
    $output = $client->call('setwall', $input);
    check_err($output, $client);
  }
}

function check_err($output, $client) {
  if ($client->fault)
    die("\n\nSoap fault: {$client->faultcode}: {$client->faultstring}\n\n");
  if (!$output['success'])
    die("\n\nMates error: {$output['response']}\n\n" . $client->response . "\n\n");
}

function microtime_float()
{
  list($usec, $sec) = explode(" ", microtime());
  return ((float)$usec + (float)$sec);
}

?>
